﻿#include "study02.h"

//#include <iostream>
//#include <cstdarg>
//#include <initializer_list>
//#include <utility>

// 使用C风格的可变参数函数（std::va_list）
// 注意：这种方式在 C++11 及之后不推荐使用，但在某些旧代码中仍然可见
// 计算可变数量的 int 参数的和
static int sum_c_style(int count, ...) {
    va_list args;
    va_start(args, count);
    int sum = 0;
    for (int i = 0; i < count; ++i) {
        sum += va_arg(args, int); // 使用va_arg获取参数值
    }
    va_end(args);
    return sum;
}

/*
使用 std::initializer_list 的可变参数函数：
    C++11引入，用于处理可变数量的相同类型的参数。
    使用方便，参数类型统一，不需要手动处理类型转换。
    适用于需要处理多个相同类型参数的情况。
*/
// 计算可变数量的 double 参数的和
double sum_initializer_list(std::initializer_list<double> values) {
    double sum = 0.0;
    for (double value : values) {
        sum += value;
    }
    return sum;
}

// 使用 C++17 折叠表达式的可变参数模板函数
// 计算可变数量的 int 参数的和
template<typename... Args>
int sum_variadic_template(Args... args) {
    return (args + ... + 0); // 使用折叠表达式计算总和，初始值为0
}
// 计算可变数量的 double 参数的和，并打印每个参数
template<typename... Args>
void print_and_sum(Args... args) {
    // 使用折叠表达式打印每个参数
    (std::cout << ... << args) << std::endl;
    // 计算总和
    std::cout << "Sum: " << (args + ... + 0.0) << std::endl;
}
// 递归求和模板函数
// 对于算术类型，递归求和；对于非算术类型，返回0
template <typename T>
auto sum_value(T first) {
    if constexpr (std::is_arithmetic_v<T>) {
        return first; // 如果是算术类型，直接返回
    }
    else {
        return 0; // 非算术类型，返回0
    }
}
template<typename T, typename... Args>
auto sum_value(T first, Args... args) {
    if constexpr (std::is_arithmetic_v<T>) {
        return first + sum_value(args...);
    }
    else {
        // 对于非算术类型，返回0
        return sum_value(args...);
    }
}

// 打印单个参数的函数
template<typename T>
void c17_print_value(T value) {
    std::cout << value << std::endl;
}
// 使用折叠表达式打印多个参数
template<typename... Args>
void c17_print_values(Args... args) {
    (c17_print_value(args), ...); // 折叠表达式用于调用每个参数的print_value函数
}

/*
C++11 标准打印多个参数的函数：
    递归模板函数：通过递归调用模板函数来处理每个参数。
    使用std::tuple和std::apply：将参数打包成一个元组，然后使用std::apply来处理元组中的每个元素。
    使用std::for_each和std::vector<std::any>：将参数存储在一个std::vector<std::any>中，然后使用std::for_each来遍历并打印每个元素。
*/
// 打印单个参数的函数
template<typename T>
void c11_print_value(T value) {
    std::cout << value << std::endl;
}
// 递归模板函数
template<typename T, typename... Args>
void c11_print_values(T first, Args... args) {
    c11_print_value(first);
    if constexpr (sizeof...(args) > 0) {
        c11_print_values(args...);
    }
}


void test_variadic_parameters() {
    print_start("C++可变参数测试");
    // 使用 C 风格的可变参数函数
    std::cout << "C风格可变参数函数求和: " << sum_c_style(3, 1, 2, 3) << std::endl;

    // 使用 std::initializer_list 的可变参数函数
    std::cout << "std::initializer_list求和: " << sum_initializer_list({1.1, 2.2, 3.3}) << std::endl;

    // 使用 C++17 折叠表达式的可变参数模板函数
    std::cout << "可变参数模板求和: " << sum_variadic_template(1, 2, 3, 4, 5) << std::endl;

    // 使用 C++17 折叠表达式的可变参数模板函数，打印并求和
    print_and_sum(1.1, 2.2, 3.3, 4.4, 5.5);

    // 递归求和模板函数
    std::cout << "递归求和模板函数: " << sum_value(1, 2.5, "hello", 4, 5) << std::endl;

    // 打印多个多种参数的函数
    std::cout << "打印多种类型的参数: " << std::endl;
    c17_print_values(1, 2.2, "三", std::string("C++17"));

    // 使用 C++11 标准打印多个参数的函数
    std::cout << "递归模板函数打印多种类型的参数: " << std::endl;
    c11_print_values(1, 2.2, "三", std::string("C++11"));
    print_end("C++可变参数测试");
}


/*
 小测试：使用模板元编程实现《一个函数传入多个多种类型的参数，分别对整数求和。浮点数求和。字符串拼接》

    模板元编程：具体来说，可以使用递归模板函数和类型判断来分别处理不同的类型。
*/
// 求整数的和
// 递归终止条件：当没有参数时，返回 0
template<typename... Args>
auto sum_integers(Args...) {
    return 0; // 终止条件：返回 0
}
// 递归处理整数求和
template<typename T, typename... Args>
auto sum_integers(T first, Args... args) {
    if constexpr (std::is_integral_v<T>) {
        return first + sum_integers(args...);
    }
    else {
        return sum_integers(args...);
    }
}

// 求浮点数的和
// 递归终止条件：当没有参数时，返回 0.0f
template<typename... Args>
auto sum_floats(Args...) {
    return 0.0f; // 终止条件
}
// 递归处理浮点数求和
template<typename T, typename... Args>
auto sum_floats(T first, Args... args) {
    if constexpr (std::is_floating_point_v<T>) {
        return first + sum_floats(args...);
    }
    else {
        return sum_floats(args...);
    }
}

// 字符串拼接
// 递归终止条件：当没有参数时，返回空字符串
template<typename... Args>
std::string concatenate_strings(Args...) {
    return ""; // 终止条件
}
// 递归处理字符串拼接
template<typename T, typename... Args>
std::string concatenate_strings(T first, Args... args) {
    std::string result; // 会自动初始化 result 为 ""
    if constexpr (std::is_same_v<T, std::string> || std::is_convertible_v<T, const char*>) {
        result += first;
    }
    else {
        //result += std::to_string(first);
        // 过滤掉非字符串类型
    }
    if constexpr (sizeof...(args) > 0) {
        // 自定义使用 + 连接字符串
        result += "+" + concatenate_strings(args...);
    }
    return result;
}

// 主处理函数
template<typename... Args>
void process_values(Args... args) {
    std::cout << "整数求和: " << sum_integers(args...) << std::endl;
    std::cout << "浮点数求和: " << sum_floats(args...) << std::endl;
    std::cout << "字符串拼接: " << concatenate_strings(args...) << std::endl;
}
/*
对上面代码的理解：

sum_integers函数：
    使用if constexpr (std::is_integral_v<t>)来判断当前参数是否为整数类型。
    如果是整数类型，则将其加到递归调用的结果中。
    如果不是整数类型，则跳过该参数并继续递归处理后续参数。

sum_floats函数：
    使用 if constexpr (std::is_floating_point_v<t>) 来判断当前参数是否为浮点类型。
    如果是浮点类型，则将其加到递归调用的结果中。
    如果不是浮点类型，则跳过该参数并继续递归处理后续参数。

concatenate_strings 函数：
    使用if constexpr来判断当前参数是否为字符串类型或可以转换为字符串类型（如 const char*）。
    如果是字符串类型，则将其直接拼接到结果中。
    如果不是字符串类型，则使用 std::to_string 将其转换为字符串后再拼接。
    继续递归处理后续参数，并在每个参数之间添加空格。

process_values函数：
    调用 sum_integers 来计算整数的和。
    调用 sum_floats 来计算浮点数的和。
    调用  concatenate_strings 来拼接字符串。
*/


void test_multiple_types() {
    print_start("模板元编程实现");
    std::cout << "处理多种类型的参数: " << std::endl;
    std::cout << "传入的参数: " << R"(1   2.2   三   std::string("四")   5   6.6   七)" << std::endl;
    process_values(1, 2.2, "三", std::string("四"), 5, 6.6, "七");
    print_end("模板元编程实现");
}
/*
constexpr 是一个关键字，用于说明一个变量、函数或函数模板可以在编译时被求值。
使用 constexpr 变量可以在编译时进行常量表达式计算，从而减少运行时的计算开销，提高程序性能。
constexpr 函数可以用于生成编译时常量，或者在其他 constexpr 表达式中使用。
*/